package edu.ccut.saturn.tag;

import java.io.IOException;
import java.io.StringWriter;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.jsp.JspWriter;
import javax.servlet.jsp.tagext.TagSupport;

import edu.ccut.saturn.tag.freemark.FreemarkerUtils;

/**
 * Titan标签抽象基类, Titan平台定义的标签应继承自该类.
 * <p>
 * 实现EL表达式解析逻辑, 通过该类可以简单操作:
 * <p>
 * <li>1, HttpRequest
 * <li>2, JspWriter
 * <li>3, 根据freemarker模板生成标签字符串内容
 * <p>
 * 
 * @author 谷钰
 * 
 * @version 1.0 2008.8.19
 */
public abstract class AbstractBaseTag extends TagSupport {

	public static final String END_ATTRIBUTE = "\" ";

	protected static final String TITAN_VALIDATE_JS_MANAGER = "__TITAN_VALIDATE_USE_INFO_LIST__";

	protected static final String TITAN_VALIDATE_ARG_NAME = "s";

	private String id = "";

	private String name = "";

	private String tagKey = null;

	public AbstractBaseTag(String tagKey) {
		this.tagKey = tagKey;
	}

	public AbstractBaseTag(String id, String name, String tagKey) {
		this.id = id;
		this.name = name;
		this.tagKey = tagKey;
	}

	/**
	 * 向页面写文本内容
	 * 
	 * @throws IOException
	 */
	public void writer(String text) throws IOException {
		this.getWriter().print(text);
	}

	/**
	 * 获得页面的输入字符流
	 * 
	 * @return
	 */
	public JspWriter getWriter() {
		return super.pageContext.getOut();
	}

	/**
	 * 根据freemarker模板以及给定的对象,向页面写文本内容
	 * 
	 * @param templatePath
	 *            模板文件路径
	 * @param value
	 *            模板中用到的值
	 * 
	 * @return 书写成功返回真
	 */
	public void writer(String templatePath, Object value) {
		Map<String, Object> values = new HashMap<String, Object>();
		values.put("tag", value);

		this.writer(templatePath, values);
	}

	/**
	 * 根据freemarker模板以及给定的<code>Map</code>,向页面写文本内容
	 * 
	 * @param templatePath
	 *            模板文件路径
	 * @param values
	 *            Map
	 * 
	 */
	public void writer(String templatePath, Map<String, ?> values) {
		JspWriter writer = this.getWriter();

		try {
			writer.write(this.getTemplateString(templatePath, values));
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} finally {
			try {
				writer.flush();
			} catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
	}

	/**
	 * 根据freemarker模板和对象自身信息,生成模板字符串
	 * 
	 * @param templatePath
	 *            模板文件路径
	 * 
	 * @return 根据模板生成字符串
	 */
	public String getTemplateString(String templatePath) {
		Map<String, Object> values = new HashMap<String, Object>();
		values.put("tag", this);

		return this.getTemplateString(templatePath, values);
	}

	/**
	 * 获得属性值。
	 * 
	 * @param parm
	 * @param parmattr
	 * @return
	 */
	public String getAttribtueStr(String parm, String parmattr) {
		if (parmattr != null && !parmattr.equals("")) {
			return parm + " = \"" + parmattr + END_ATTRIBUTE;
		}
		
		return "";
	}
	
	public String getAttribtueStr(String parm, String parmattr, String defaultValue) {
		if (parmattr != null && !parmattr.equals("")) {
			return parm + " = \"" + parmattr + END_ATTRIBUTE;
		}
		
		return parm + " = \"" + defaultValue + END_ATTRIBUTE;
	}

	private String getTemplateString(String templatePath, Map<String, ?> values) {
		StringWriter writer = new StringWriter();
		String content = "";

		try {
			FreemarkerUtils.writeTemplate(templatePath, values, writer);

			content = writer.toString();
		} catch (RuntimeException e) {
			e.printStackTrace();
		} finally {
			try {
				writer.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}

		return content;
	}

	/**
	 * 获得HttpServletRequest对象
	 * 
	 * @return HttpServletRequest对象
	 */
	public HttpServletRequest getRequest() {
		return (HttpServletRequest) super.pageContext.getRequest();
	}

	// TODO:放在这里是否合理
//	public ValidateJSManager getValidateJSManager() {
//		if (this.getRequest().getAttribute(TITAN_VALIDATE_JS_MANAGER) != null) {
//			return (ValidateJSManager) this.getRequest().getAttribute(
//					TITAN_VALIDATE_JS_MANAGER);
//		}
//		return null;
//
//	}

	// TODO:放在这里是否合理?
	public String getWarnSubmitName() {
		if (this.getRequest().getAttribute("_SUBMIT_WARN_NAME_") != null) {
			return this.getRequest().getAttribute("_SUBMIT_WARN_NAME_")
					.toString();
		}
		return "";
	}

	// TODO:放在这里是否合理?
	public String getValidateSubmitName() {
		if (this.getRequest().getAttribute("_FORM_VALIDATE_SUBMIT_") != null) {
			return this.getRequest().getAttribute("_FORM_VALIDATE_SUBMIT_")
					.toString();
		}
		return "";
	}

	public String getId() {
		return id;
	}

	public String getIdAttr() {
		return getAttribtueStr("id", this.id);
	}

	public void setId(String id) {
		this.id = id;
	}

	public String getName() {
		return name;
	}

	public String getNameAttr() {
		return getAttribtueStr("name", this.name);
	}

	public void setName(String name) {
		this.name = name;
	}

	public String getTagKey() {
		return tagKey;
	}

	public void setTagKey(String tagKey) {
		this.tagKey = tagKey;
	}

	/**
	 * 实现解析EL表达式
	 * 
	 * @param str
	 * 
	 * @return 返回EL表达式解析的结果
	 */
	public Object getExpressValueObject(String str) {
		String nullStr = "";

		if (!this.isHasExpress(str)) {
			return str;
		}

		if (this.isSimpleExpress(str)) {
			Object value = this.getExpressValue(str.substring(2,
					str.length() - 1));
			if (value != null) {
				return value;
			} else {
				return nullStr;
			}
		} else {
			int startIndex = str.indexOf("${");
			int endIndex = str.indexOf('}', startIndex + 1);

			String first = "";
			if (startIndex > 0) {
				first = str.substring(0, startIndex);
			}

			String end = "";
			if (endIndex < str.length() - 1) {
				end = str.substring(endIndex + 1);
			}

			String subExp = str.substring(startIndex + 2, endIndex);
			Object value = this.getExpressValue(subExp);

			if (value != null) {
				return getExpressValueObject(first + value + end);
			} else {
				return getExpressValueObject(first + "{" + subExp + "}" + end);
			}
		}
	}

	private boolean isHasExpress(String str) {
		if (str == null) {
			return false;
		}

		int startIndex = str.indexOf("${");
		int endIndex = str.indexOf("}");

		if (startIndex >= 0 && endIndex >= 0 && endIndex > startIndex) {
			return true;
		}

		return false;
	}

	private boolean isSimpleExpress(String str) {
		if (str.startsWith("${") && str.indexOf('}') == str.length() - 1) {
			return true;
		}

		return false;
	}

	private Object getExpressValue(String exp) {
		if ("pageContext.request.contextPath".equals(exp)) {
			return this.getRequest().getContextPath();
		}

		int index = exp.indexOf('.');

		String key = null;
		if (index >= 0) {
			key = exp.substring(0, index);
		} else {
			key = exp;
		}

		Object value = this.getValueFromRequestSessionApplication(key);
		if (value != null && index >= 0) {
			String subExp = exp.substring(index + 1);

			return this.getValueFromExperss(value, subExp);
		}

		return value;
	}

	public Object getValueFromExperss(Object value, String exp) {
		int index = exp.indexOf('.');

		if (index < 0) {
			try {
				return this.getValueFromName(value, exp);
			} catch (Exception e) {
				e.printStackTrace();
			}
		} else {
			String subExp = exp.substring(index + 1);
			String oriExp = exp.substring(0, index);

			Object subValue = null;

			try {
				subValue = this.getValueFromName(value, oriExp);
			} catch (Exception e) {
				e.printStackTrace();
			}

			if (subValue != null) {
				return this.getValueFromExperss(subValue, subExp);
			}
		}

		return null;
	}

	private Object getValueFromRequestSessionApplication(String exp) {
		if (this.pageContext.getAttribute(exp) != null) {
			return this.pageContext.getAttribute(exp);
		}

		if (this.pageContext.getRequest().getAttribute(exp) != null) {
			return this.pageContext.getRequest().getAttribute(exp);
		}

		if (this.pageContext.getRequest().getParameter(exp) != null) {
			return this.pageContext.getRequest().getParameter(exp);
		}

		if (this.pageContext.getRequest().getParameterValues(exp) != null) {
			return this.pageContext.getRequest().getParameterValues(exp);
		}

		if (this.pageContext.getSession().getAttribute(exp) != null) {
			return this.pageContext.getSession().getAttribute(exp);
		}

		return this.pageContext.getServletContext().getAttribute(exp);
	}

	@SuppressWarnings("unchecked")
	private Object getValueFromName(Object value, String name) throws Exception {
		if (value instanceof Map) {
			return ((Map) value).get(name);
		}

		Method getMethod = value.getClass().getMethod(
				"get" + Character.toUpperCase(name.charAt(0))
						+ name.substring(1), new Class[] {});

		return getMethod.invoke(value, new Object[] {});
	}
}
